////////////////////////////////////////////////////////////////////////////////
//
//  FLEX USER GROUP HOKURIKU
//  Copyright 2009 Flex User Group Hokuriku
//  All Rights Reserved.
// 
//  NOTICE: Flex User Group Hokuriku permits you to use, 
//  modify, and distribute this file 
//  in accordance with the terms of the license agreement accompanying it.
//
////////////////////////////////////////////////////////////////////////////////
package net.fxug.hokuriku.chocolat.service
{
    import com.adobe.errors.IllegalStateError;
    import com.adobe.serialization.json.JSON;

    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.HTTPStatusEvent;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;

    import mx.logging.ILogger;

    import net.fxug.hokuriku.chocolat.events.A3TNDEvent;
    import net.fxug.hokuriku.chocolat.model.A3TNDEventSearchCriteria;
    import net.fxug.hokuriku.chocolat.model.A3TNDUserSearchCriteria;
    import net.fxug.hokuriku.chocolat.model.constants.a3tndConstants;
    import net.fxug.hokuriku.chocolat.utils.JSONDataParser;
    import net.fxug.hokuriku.chocolat.utils.LoggingUtil;

    /**
     * 検索成功時
     * @eventType net.fxug.hokuriku.chocolat.events.A3TNDEvent.COMPLETE_EVENT
     */
    [Event(name="completeEvent", type="net.fxug.hokuriku.chocolat.events.A3TNDEvent")]
    /**
     * 検索失敗時
     * @eventType net.fxug.hokuriku.chocolat.events.A3TNDEvent.FAILED_EVENT
     */
    [Event(name="failedEvent", type="net.fxug.hokuriku.chocolat.events.A3TNDEvent")]
    /**
     * 状態変更時
     * @eventType net.fxug.hokuriku.chocolat.events.A3TNDEvent.STATUS_EVENT
     */
    [Event(name="statusEvent", type="net.fxug.hokuriku.chocolat.events.A3TNDEvent")]

    /**
     * ATND検索用クラス。
     * @example	<listing version="3.0">
     * 				var a3tnd:A3TND = new A3TND();
     *				var criteria:A3TNDEventSearchCriteria;
     * 				a3tnd.eventSearch(criteria);
     * 			</listing>
     * @author hikaruworld
     *
     * TODO idleTimeoutの実装
     */
    public class A3TND extends EventDispatcher
    {
        /** イベントサーチURL */
        private static const EVENT_SEARCH_URL:String = "http://api.atnd.org/events/?";
        /** 出欠確認URL */
        private static const EVENT_USER_URL:String = "http://api.atnd.org/events/users/?";

		/** ロガー */
        private static var logger:ILogger = LoggingUtil.getLogger(A3TND);

		/** 検索に用いられるURLLoader */
		private var urlLoader:URLLoader;
        /** 検索タイプ */
        private var searchType:int;

        /** デフォルトコンストラクタ */
        public function A3TND()
        {
            this.init();
        }

        /**
         * 初期化メソッド
         */
        private function init():void
        {
            urlLoader = new URLLoader();
            urlLoader.addEventListener(Event.COMPLETE, completeHandler);
            urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
            urlLoader.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
            urlLoader.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
        }

        /**
         * イベント検索を行う
         * @param criteria 検索条件
         */
        public function eventSearch(criteria:A3TNDEventSearchCriteria):void
        {
            this.searchType = a3tndConstants.SEARCH_TYPE_EVENT;
            var searchQuery:String = EVENT_SEARCH_URL + encodeURI(criteria.createQuery());
            logger.info(searchQuery);
            this.urlLoader.load(new URLRequest(searchQuery));
        }

        /**
         * 出欠状況検索を行う
         * @param criteria 検索条件
         */
        public function attendanceSearch(criteria:A3TNDUserSearchCriteria):void
        {
            this.searchType = a3tndConstants.SEARCH_TYPE_USER;
            var searchQuery:String = EVENT_USER_URL + encodeURI(criteria.createQuery());
            logger.info(searchQuery);
            this.urlLoader.load(new URLRequest(searchQuery));
        }

        /**
         * ロード完了時に実行されるイベントハンドラ
         * @param event URLLoaderによってロードされたイベント情報
         */
        private function completeHandler(event:Event):void
        {
            logger.info("a3tnd search completeHandler-------------");
			logger.debug(this.urlLoader.data);
            var decodeResult:Object = JSON.decode(this.urlLoader.data);

            var a3tndEvent:A3TNDEvent;
            switch (this.searchType)
            {
                case a3tndConstants.SEARCH_TYPE_EVENT:
                    var eventResult:Array = JSONDataParser.parseEventsSearchResultArray(decodeResult);
                    a3tndEvent = new A3TNDEvent(A3TNDEvent.COMPLETE_EVENT, eventResult);
                    break;

                case a3tndConstants.SEARCH_TYPE_USER:
                    var userResult:Array = JSONDataParser.parseUsersSearchResultArray(decodeResult)
                    a3tndEvent = new A3TNDEvent(A3TNDEvent.COMPLETE_EVENT, userResult);
                    break;

                default:
                    throw new IllegalStateError("プロパティ[ " + this.searchType + " ]は存在しないため処理できません。");
            }
            this.dispatchEvent(a3tndEvent);
        }

		/**
         * HTTPステータスを返すイベントハンドラ
		 * @param httpStatusEvent flash.events.HTTPStatusEvent
		 */		
        private function httpStatusHandler(httpStatusEvent:HTTPStatusEvent):void
        {
			logger.debug("httpStatusHandler status {0}" + httpStatusEvent.status);
            this.dispatchEvent(new A3TNDEvent(A3TNDEvent.STATUS_EVENT, null, httpStatusEvent.status as String));
        }

		/**
         * セキュリティエラー発生時のイベントハンドラ
		 * @param securityErrorEvent flash.events.SecurityErrorEvent
		 * 
		 */		
        private function securityErrorHandler(securityErrorEvent:SecurityErrorEvent):void
        {
			logger.error("securityErrorHandler errorId:{0}, text:{1}", securityErrorEvent.errorID, securityErrorEvent.text);
            this.dispatchEvent(new A3TNDEvent(A3TNDEvent.FAILED_EVENT, null, securityErrorEvent.text));
        }

        /**
         * IOエラー発生時のイベントハンドラ
		 * @param ioErrorEvent flash.events.IOErrorEvent
         */
        private function ioErrorHandler(ioErrorEvent:IOErrorEvent):void
        {
			logger.error("ioErrorHandler errorId:{0}, text:{1}", ioErrorEvent.errorID, ioErrorEvent.text);
            this.dispatchEvent(new A3TNDEvent(A3TNDEvent.FAILED_EVENT, null, ioErrorEvent.text));
        }
    }
}